package com.xinlan.imageeditlibrary.editimage.view;

import com.xinlan.imageeditlibrary.editimage.utils.DeviceUtils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.IntegerRes;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

/**
 * 标尺类
 */
@SuppressLint("NewApi")
public class RulerView extends View {
	// getSimpleName()返回源代码中给出的底层类的简称。
	final String TAG = RulerView.class.getSimpleName();
	// 开始范围
	private int mBeginRange;
	// 结束范围
	private int mEndRange;
	/** 内部宽度，也就是标尺每条的宽度 */
	private int mInnerWidth;
	// 标尺条目间的间隔
	private int mIndicatePadding;
	// 显示的画笔
	private Paint mIndicatePaint;
	// 文字画笔
	private Paint mTextPaint;
	// 显示的宽度
	private int mIndicateWidth;
	// 显示的大小
	private float mIndicateScale;
	// 是否自动匹配
	private boolean mIsAutoAlign = true;
	// 是否需要显示文字
	private boolean mIsWithText = true;
	// 文字颜色
	private int mTextColor;
	// 文字大小
	private float mTextSize;
	// 标尺的颜色
	private int mIndicateColor;
	// 标尺条显示的位置：top，bottom
	private int mGravity;
	/** 标尺矩形（刻度条） */
	private Rect mIndicateLoc;

	public RulerView(Context context) {
		this(context, null);
	}

	public RulerView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	/**
	 * 最终都是调用此构造方法
	 *
	 * @param context
	 * @param attrs
	 * @param defStyleAttr
	 */
	public RulerView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);

		int[] devices=DeviceUtils.getScreenSizeInt(context);
		int screenwidth=devices[0];
		
		mIndicateColor = Color.BLACK;
		mTextColor = Color.RED;
		mTextSize =  18;
		mBeginRange = 0;
		mEndRange = screenwidth/40;
		// 标尺宽度
		mIndicateWidth = 4;
		// 标尺的间隙
		mIndicatePadding = 16;
		mGravity = Gravity.TOP;
		// 默认显示比例为0.7倍
		mIndicateScale = 0.6f;

		initValue();
	}

	/**
	 * 初始化数值
	 */
	private void initValue() {

		// 设置标尺的画笔，实心画
		mIndicatePaint = new Paint();
		mIndicatePaint.setStyle(Paint.Style.FILL);
		// 设置文字画笔，实心画，并消除锯齿
		mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mTextPaint.setStyle(Paint.Style.FILL);
		mTextPaint.setColor(mTextColor);
		mTextPaint.setTextAlign(Paint.Align.CENTER);
		mTextPaint.setTextSize(mTextSize);
		// 内部宽度（标尺结束范围-标尺开始范围）*指示宽度
		mInnerWidth = (mEndRange - mBeginRange) * getIndicateWidth();
		// 标尺定位为一个矩形
		mIndicateLoc = new Rect();

	}

	/**
	 * 重写绘制方法
	 *
	 * @param canvas
	 */
	@Override
	protected void onDraw(Canvas canvas) {

		/**
		 * 当我们对画布进行旋转，缩放，平移等操作的时候其实我们是想对特定的元素进行操作，
		 * 比如图片，一个矩形等，但是当你用canvas的方法来进行这些操作的时候， 其实是对整个画布进行了操作，那么之后在画布上的元素都会受到影响，
		 * 所以我们在操作之前调用canvas.save()来保存画布当前的状态， 当操作之后取出之前保存过的状态，这样就不会对其他的元素进行影响
		 */
		int count = canvas.save();
		// 循环绘制标尺条（刻度），根据最大值和最小值来绘制
		for (int value = mBeginRange, position = 0; value <= mEndRange; value++, position++) {
			drawIndicate(canvas, position);
			// 如果需要数字，还需要在刻度下绘制数字
			if (mIsWithText)
				drawText(canvas, position, String.valueOf(value));

		}

		// 恢复Canvas的状态
		canvas.restoreToCount(count);

	}

	/**
	 * 绘制标尺条（刻度），0到100就会显示100个刻度
	 * 
	 * @param canvas
	 *            画布
	 * @param position
	 */
	private void drawIndicate(Canvas canvas, int position) {
		computeIndicateLoc(mIndicateLoc, position);
		int left = mIndicateLoc.left + mIndicatePadding;
		int right = mIndicateLoc.right - mIndicatePadding;
		int top = mIndicateLoc.top;
		int bottom = mIndicateLoc.bottom;

		if (position % 2 != 0) {
			int indicateHeight = bottom - top;
			if (isAlignTop()) {
				bottom = (int) (top + indicateHeight * mIndicateScale);
			} else {
				top = (int) (bottom - indicateHeight * mIndicateScale);
			}
		}

		mIndicatePaint.setColor(mIndicateColor);
		canvas.drawRect(left, top, right, bottom, mIndicatePaint);
	}

	/**
	 * 绘制文字，每5个刻度绘制一个文字用于提示
	 * 
	 * @param canvas
	 * @param position
	 * @param text
	 */
	private void drawText(Canvas canvas, int position, String text) {
		if (position % 2 != 0)
			return;
		computeIndicateLoc(mIndicateLoc, position);
		int textHeight = computeTextHeight();

		mTextPaint.setColor(mTextColor);
		mTextPaint.setTextSize(mTextSize);
		mTextPaint.setTextAlign(Paint.Align.CENTER);

		int x = (mIndicateLoc.left + mIndicateLoc.right) / 2;
		int y = mIndicateLoc.bottom + textHeight;

		if (!isAlignTop()) {
			y = mIndicateLoc.top;
			mTextPaint.getTextBounds(text, 0, text.length(), mIndicateLoc);
			y += mIndicateLoc.top / 2; // 增加一些偏移
		}
		text=Integer.parseInt(text)*40+"";
		canvas.drawText(text, x, y, mTextPaint);
	}

	/**
	 * 计算指示器的位置：设置左上右下 最终是设置了此矩形（刻度的左上右下）
	 * 
	 * @param outRect
	 *            矩形
	 * @param position
	 *            位置数值（代表第几个刻度）
	 */
	private void computeIndicateLoc(Rect outRect, int position) {
		if (outRect == null)
			return;

		int height = getHeight();
		int indicate = getIndicateWidth();

		int left = (indicate * position);
		int right = left + indicate;
		int top = getPaddingTop();// 获得当前View的顶内距
		int bottom = height - getPaddingBottom();// 视图高度-视图低内距

		if (mIsWithText) {
			int textHeight = computeTextHeight();
			if (isAlignTop())
				bottom -= textHeight;// 如果是刻度显示在顶部，底部要减去文字的高度
			else
				top += textHeight;// 如果是刻度显示在底部，顶部要加上文字的高度
		}
		// 文字偏移量，左边和右边都加上一个偏移量
		int offsets = getStartOffsets();
		left += offsets;
		right += offsets;
		outRect.set(left, top, right, bottom);
	}

	/**
	 * 开始偏移，如果要包含文字的话才需要偏移。
	 *
	 * @return
	 */
	private int getStartOffsets() {
		if (mIsWithText) {
			String text = String.valueOf(mBeginRange);
			// 返回文字的宽度
			int textWidth = (int) mTextPaint.measureText(text, 0, text.length());
			return textWidth / 2;// 实际偏移文字宽度的一半，使其居中显示
		}
		return 0;
	}

	/**
	 * 刷新参数值
	 */
	private void refreshValues() {
		// 内部宽度 = （最大值-开始值）*刻度宽度
		mInnerWidth = (mEndRange - mBeginRange) * getIndicateWidth();
		invalidateView();

	}

	/**
	 * 最终指示宽度 ：刻度宽度+刻度内边距+刻度内边距
	 *
	 * @return
	 */
	private int getIndicateWidth() {
		return mIndicateWidth + mIndicatePadding + mIndicatePadding;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	/**
	 * 计算文字高度
	 * 
	 * @return
	 */
	private int computeTextHeight() {
		// 使用FontMetrics对象，计算文字的坐标。
		Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
		float textHeight = fontMetrics.descent - fontMetrics.ascent;
		return (int) textHeight;
	}

	private boolean isAlignTop() {
		// &为位运算符，就是32位二进制值得比较
		return (mGravity & Gravity.TOP) == Gravity.TOP;
	}

	public void setGravity(int gravity) {
		this.mGravity = gravity;
		invalidateView();
	}

	/**
	 * 刷新界面 如果版本大于16（4.1） 使用postInvalidate可以直接在线程中更新界面 invalidate()必须在UI线程中使用
	 */
	public void invalidateView() {
		if (Build.VERSION.SDK_INT >= 16) {
			postInvalidateOnAnimation();
		} else
			invalidate();
	}

	/**
	 * 设置刻度的宽度
	 * 
	 * @param indicateWidth
	 */
	public void setIndicateWidth(@IntegerRes int indicateWidth) {
		this.mIndicateWidth = indicateWidth;
		refreshValues();
	}

	/**
	 * 设置刻度内间距
	 * 
	 * @param indicatePadding
	 */
	public void setIndicatePadding(@IntegerRes int indicatePadding) {
		this.mIndicatePadding = indicatePadding;
		refreshValues();
	}

	public void setWithText(boolean withText) {
		this.mIsWithText = withText;
		refreshValues();
	}

	public void setAutoAlign(boolean autoAlign) {
		this.mIsAutoAlign = autoAlign;
		refreshValues();
	}

	/**
	 * 是否显示文字
	 * 
	 * @return
	 */
	public boolean isWithText() {
		return mIsWithText;
	}

	/**
	 * 自动对齐刻度
	 * 
	 * @return
	 */
	public boolean isAutoAlign() {
		return mIsAutoAlign;
	}
}
